package ru.tusur.asu.pnn.executable;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import com.nativelibs4java.opencl.CLDevice;
import com.nativelibs4java.opencl.CLPlatform;
import com.nativelibs4java.opencl.InfoName;
import com.nativelibs4java.opencl.JavaCL;

/**
 * Class for gathering platform info.
 * @author vvs
 *
 */
public class PlatformInfo {
	
	public static void main(String[] args) {
		for (CLPlatform platform : JavaCL.listPlatforms()) {
			printHardwareReport(platform);
		}
	}

	private static void printHardwareReport(CLPlatform platform) {
		System.out.println("Platform: " + platform.getName());
		System.out.println();
		
		Map<String, Method> deviceMethods = getInfoMethods(CLDevice.class);
		
		for (CLDevice device : platform.listAllDevices(false)) {
			System.out.println("Device: " + device.getName());
			System.out.println();
			
			for (Map.Entry<String, Method> deviceMethod : deviceMethods.entrySet()) {
				try {
					String name = deviceMethod.getKey();
					Object value = deviceMethod.getValue().invoke(device);
					System.out.println(name + " : " + objectToString(value));
				} catch (InvocationTargetException ex) {
					if (!(ex.getCause() instanceof UnsupportedOperationException)) {
						throw new RuntimeException(ex);
					}
				} catch (IllegalAccessException e) {
					continue;
				}
			}
		}
	}
	
	private static String objectToString(Object value) {
		if (value == null) return "null";
		if (value instanceof boolean[]) {
			return Arrays.toString((boolean[])value);
		} 
		if (value instanceof char[]) {
			return Arrays.toString((char[])value);
		} 
		if (value instanceof byte[]) {
			return Arrays.toString((byte[])value);
		}
		if (value instanceof short[]) {
			return Arrays.toString((short[])value);
		}
		if (value instanceof int[]) {
			return Arrays.toString((int[])value);
		}
		if (value instanceof long[]) {
			return Arrays.toString((long[])value);
		}
		if (value instanceof float[]) {
			return Arrays.toString((float[])value);
		}
		if (value instanceof double[]) {
			return Arrays.toString((double[])value);
		}
		if (value instanceof Object[]) {
			return Arrays.toString((Object[])value);
		}
		return value.toString();
	}
	
	private static Map<String, Method> getInfoMethods(Class<?> c) {
		Map<String, Method> res = new HashMap<String, Method>();
		for (Method method : c.getMethods()) {
			InfoName name = method.getAnnotation(InfoName.class);
			if (name != null) {
				res.put(name.value(), method);
			}
		}
		return res;
	}
}
